//
// Created by nilyang on 2022/2/19.
//

#include <tuple>
#include <array>
#include <iostream>
#include "include.h"
#include "stl_tuple_iteration.h"

using namespace std::string_literals;


template<typename Tuple, typename Functor, int Index>
constexpr void foreach_tuple_via_recursive_template_impl(Tuple &&t, Functor &&f) {
    if constexpr (Index >= std::tuple_size<std::remove_reference_t<Tuple>>::value) {
        return;
    } else {
        f(std::get<Index>(t));
        foreach_tuple_via_recursive_template_impl<Tuple, Functor, Index + 1>(std::forward<Tuple>(t),
                                                                             std::forward<Functor>(f));
    }
}

template<typename Tuple, typename Functor>
constexpr void foreach_tuple_via_recursive_template(Tuple &&t, Functor &&f) {
    foreach_tuple_via_recursive_template_impl<Tuple, Functor, 0>(std::forward<Tuple>(t), std::forward<Functor>(f));
}


template<typename Tuple, typename Functor, size_t... Is>
constexpr void foreach_tuple_via_fold_expression_impl(Tuple &t, Functor &&f, std::index_sequence<Is...>) {
    (f(std::get<Is>(t)), ...);
}


template<typename Tuple, typename Functor>
constexpr void foreach_tuple_via_fold_expression(Tuple &t, Functor &&f) {
    foreach_tuple_via_fold_expression_impl(t, std::forward<Functor>(f),
                                           std::make_index_sequence<std::tuple_size_v<Tuple>>());
}

void func_test_foreach_tuple_via_recursive_template() {
    std::cout << "\ntuple_for_each 遍历tuple" << std::endl;
    foreach_tuple_via_recursive_template(
            std::make_tuple(1, 2, 3, "hello", "world", 3.1415, 2.7183),
            [](const auto &element) {
                std::cout << " " << element << std::endl;
            }
    );

}

void func_test_foreach_tuple_via_fold_expression()
{
    std::array ints{13, 22, 43};
    std::array floats{32.71, 23.14};
    std::array strs{"helloxx"s, "worffld"s, "a?!"s};
    auto tuple_values = std::make_tuple(ints, floats, strs);
    //auto size = std::tuple_size<decltype(tuple_values)>::value;
    std::cout << "\n 折叠表达式 Hello fold_expression \n";
    foreach_tuple_via_fold_expression(tuple_values, Print{';'});
}

void func_test_recursive_and_fold_expression() {
    std::array ints{1, 2, 3};
    std::array floats{2.71, 3.14};
    std::array strs{"hello"s, "world"s, "?!"s};

    auto tuple_values = std::make_tuple(ints, floats, strs);
    //auto size = std::tuple_size<decltype(tuple_values)>::value;

    std::cout << "\n 递归模板 constexpr if 递归边界条件\n";
    foreach_tuple_via_recursive_template(tuple_values, Print{','});

    std::cout << "\n 折叠表达式 Hello fold_expression \n";
    foreach_tuple_via_fold_expression(tuple_values, Print{';'});
}


